package com.creative.user.controller;

import cn.dev33.satoken.stp.SaTokenInfo;
import cn.dev33.satoken.stp.StpUtil;
import cn.dev33.satoken.util.SaResult;
import cn.hutool.core.util.*;
import cn.hutool.log.Log;
import cn.hutool.log.LogFactory;
import com.creative.annotation.VerifyParam;
import com.creative.config.AppConfig;
import com.creative.constant.Constants;
import com.creative.core.domain.AjaxResult;
import com.creative.core.uitls.DateUtils;
import com.creative.core.uitls.Uidutil;
import com.creative.user.domain.UserInfo;
import com.creative.user.domain.dto.*;
import com.creative.user.service.UserInfoService;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import javax.annotation.Resource;
import javax.servlet.http.HttpSession;
import javax.validation.Valid;
import java.util.HashMap;
import java.util.Map;

import static com.creative.constant.Constants.EMAIL_CODE;
import static com.creative.constant.Constants.USER_CODE;
import static com.creative.user.domain.UserInfoConstants.*;

/**
 * 登录控制器
 */
@RestController
@Validated
@RequestMapping("/user/")
@Transactional(rollbackFor = Exception.class)
public class LoginController {

    @Resource
    private UserInfoService userInfoService;

    @Resource
    private com.creative.utils.RedisUtils RedisUtils;

    @Resource
    private AppConfig appConfig;

    @Resource
    private StringRedisTemplate stringRedisTemplate;

    private static final Log logger = LogFactory.get();

    /**
     * 登录
     *
     * @param loginDto 登录对象信息
     * @return {@link SaResult }
     * @author ling
     * @date 2024/11/18
     */
    @PostMapping("login")
    public AjaxResult doLogin(@Valid @RequestBody LoginDto loginDto) {
//        验证账号、密码是否正确    名字和密码具有唯一性
//      对参数进行验证    对密码进行解密 md5
        String name = loginDto.getName();
        String pwd = loginDto.getPassword();
//      给密码加密
//        String pwdMd5 = SecureUtil.md5(pwd);
//      验证用户是否存在
        UserInfo user = userInfoService.selectByNameAndPassword(name, pwd);
        logger.info("用户名：" + name + " 密码：" + pwd);
        if (ObjectUtil.hasEmpty(user)) {
            return AjaxResult.error("账号或密码错误");
        }

//        判断账号是否禁用
        if (STATUS_DISABLE.equals(user.getStatus())) {
            return AjaxResult.error("账号已被禁用");
        }

        String code = loginDto.getCode();

//        根据前端传递的uuid ， 来查询验证码
        String value = stringRedisTemplate.opsForValue().get(USER_CODE + loginDto.getUuid());

        if (StrUtil.isEmpty(value)) {
            return AjaxResult.error("验证码已过期");
        }
//        忽略大小写
        code = code.toLowerCase();
        value = value.toLowerCase();
//        logger.info("redis验证码：" + value);
//        logger.info("code:" + code);
        if (!code.equals(value)) {
            return AjaxResult.error("验证码错误");
        }

//        运用saToken 加入用户id     设置登录状态
        String userId = user.getUserId();
        StpUtil.login(userId);

//  saToken（存入Account Session中）  在登录时缓存 user 对象
        StpUtil.getSession().set("loginUser" + userId, loginDto);

//        将token信息传递给前端
//        获取token信息
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();
//        存在
        //        tokeninfo 的内容
/*         [tokenName=satoken,
                tokenValue=ea2a4c99-fbfd-4ff1-8980-e36aa155d7f0,
                isLogin=true, loginId=565114865852037,
                loginType=login,
                tokenTimeout=7200,
                sessionTimeout=2531322,
                tokenSessionTimeout=-2,
                tokenActiveTimeout=-1,
                loginDevice=default-device, tag=null]*/

//        加入redis缓存 、 无需手动写入 satoken自动写入
//        stringRedisTemplate.opsForValue().set(TOKEN_INFO, tokenInfo.toString());


//        更新用户的上次登录时间
        user.setLastLoginTime(DateUtils.getNowDate());
        userInfoService.update(user);
//      获取token凭证
        String token = tokenInfo.getTokenValue();
//        判断是否是管理员
//        判断用户的管理员权限
//        if (ArrayUtil.contains(appConfig.getAdminEmails().split(","), loginuserInfo.getEmail())){
//            sessionWebDto.setIsAdmin(true);
//        }else {
//            sessionWebDto.setIsAdmin(false);
//        }

        SessionWebDto sessionWebDto = SessionWebDto.builder()
                .nickName(user.getNickName())
                .userId(user.getUserId())
                .isAdmin(ArrayUtil.contains(appConfig.getAdminEmails().split(","), user.getEmail() == null ? "" : user.getEmail()))
                .avatar(user.getAvatar())
                .tokenInfo(token)
                .build();

        StpUtil.getSession().set("WebSession" + userId, sessionWebDto);
//        用户空间

        UserSpaceDto userSpaceDto = UserSpaceDto.builder()
                .useSpace(user.getUseSpace())
                .totalSpace(user.getTotalSpace())
                .build();
//       在reids中保存 用户空间的使用情况
        RedisUtils.saveUserSpace(userId, userSpaceDto);
//       更新redis中的数据
        StpUtil.getSession().update();

        return AjaxResult.success(sessionWebDto);
    }

    // 查询登录状态  ---- http://localhost:8081/acc/isLogin
    @RequestMapping("isLogin")
    public SaResult isLogin() {
        logger.info("是否登录：" + StpUtil.isLogin());
        return SaResult.ok("是否登录：" + StpUtil.isLogin());
    }

    // 查询 Token 信息  ---- http://localhost:8081/acc/tokenInfo
    @RequestMapping("tokenInfo")
    public SaResult tokenInfo() {
        logger.info("Token 专属信息：" + StpUtil.getTokenInfo());
        return SaResult.data(StpUtil.getTokenInfo());
    }

    // 测试注销  ---- http://localhost:8081/acc/logout
    @RequestMapping("logout")
    public SaResult logout() {
        StpUtil.logout();
        return SaResult.ok();
    }

    /**
     * 注册
     *
     * @param registerDto 注册dto
     * @return {@link AjaxResult }
     * @author ling
     * @date 2024/11/18
     */
    @PostMapping("register")
    public AjaxResult register(@Valid @RequestBody RegisterDto registerDto) {
        logger.info("注册用户,registerDto:{}", registerDto);

        if (ObjectUtil.hasEmpty(registerDto)) {
            return AjaxResult.error("数据异常");
        }
        String name = registerDto.getUsername();
        String pwd = registerDto.getPassword();
        UserInfo userinfo = userInfoService.selectByNameAndPassword(name, pwd);
        logger.info("用户名：" + name + " 密码：" + pwd);
        if (ObjectUtil.isNotEmpty(userinfo)) {
            return AjaxResult.error("账号已存在");
        }
        //        从数据库中查询 email 是否已经注册过
        UserInfo userByEmail = userInfoService.selectByEmail(registerDto.getEmail());
        if (ObjectUtil.isNotEmpty(userByEmail)) {
            return AjaxResult.error("邮箱已注册");
        }

        if (!registerDto.getPassword().equals(registerDto.getRepassword())) {
            AjaxResult.error("两次密码不一致！");
        }

//        登录  判断eamil 验证码是否正确
        String emailCode = stringRedisTemplate.opsForValue().get(EMAIL_CODE + registerDto.getEmail());

        if (!registerDto.getEcode().equals(emailCode)) {
            return AjaxResult.error("验证码错误");
        }
//      随机生成uid (10位以内)
        String uid = Uidutil.generateUid(10);
//        logger.info("生成uid:{}", uid);
        UserInfo user = new UserInfo();
        user.setUserId(uid);
        user.setNickName(registerDto.getUsername());
//        对密码进行加密
//        String Password = SecureUtil.md5(registerDto.getPassword());
        user.setPassword(registerDto.getPassword());
        user.setCreateTime(DateUtils.getNowDate());
        user.setLastLoginTime(DateUtils.getNowDate());
        user.setEmail(registerDto.getEmail());
//        启用账号
        user.setStatus(STATUS);
        user.setUseSpace(USE_SPACE);
        user.setTotalSpace(TOTAL_SPACE * MB);
        user.setDelFlag(DEL_FLAG);
//        添加用户
        userInfoService.insert(user);

        return AjaxResult.success();
    }

    /**
     * 通过电子邮件注册/登录
     *
     * @param emailDto 电子邮件至
     * @return {@link AjaxResult }
     * @author ling
     * @date 2024/11/29
     */
    @PostMapping("registeEmail")
    public AjaxResult registerByEmail(@Valid @RequestBody EmailDto emailDto) {
//        判断数据是否为空
        if (ObjectUtil.hasEmpty(emailDto)) {
            return AjaxResult.error("邮箱数据为空");
        }

        logger.info("邮箱注册：" + emailDto);
        String email = emailDto.getEmail();
        String ecode = emailDto.getEcode();
//        从数据库中查询 email 是否已经注册过
        UserInfo user = userInfoService.selectByEmail(email);
        logger.info("用户：" + user);
        //        如果没有注册过，则创建账号
        UserInfo userInfo = new UserInfo();
        if (ObjectUtil.isEmpty(user)) {
            //        如果没有注册过，则创建账号
            userInfo.setEmail(email);
            userInfo.setCreateTime(DateUtils.getNowDate());
            userInfo.setLastLoginTime(DateUtils.getNowDate());
//        启用账号
            userInfo.setStatus(STATUS);
            userInfo.setUseSpace(USE_SPACE);
            userInfo.setTotalSpace(TOTAL_SPACE * MB);
            userInfo.setDelFlag(DEL_FLAG);
            //      随机生成uid (10位以内)
            String uid = Uidutil.generateUid(10);
            userInfo.setUserId(uid);
//            使用用户的默认用户名
            userInfo.setNickName("user" + uid.substring(0, 1) + RandomUtil.randomNumbers(4));
            //        添加用户
            userInfoService.insert(userInfo);
        }

//        登录  判断eamil 验证码是否正确
        String emailCode = stringRedisTemplate.opsForValue().get(EMAIL_CODE + email);

        if (!ecode.equals(emailCode)) {
            return AjaxResult.error("验证码错误");
        }
        String userId = null;
//      如果当前邮箱有账号，则获取用户id
        if (ObjectUtil.isNotEmpty(user)) {
            userId = user.getUserId();
            //        运用saToken 加入用户id     设置登录状态
            StpUtil.login(userId);
            //  saToken（存入Account Session中）  在登录时缓存 user 对象
            StpUtil.getSession().set("user" + userId, user);
//            缓存一些用户的信息
            //        更新用户的上次登录时间
            user.setLastLoginTime(DateUtils.getNowDate());
            userInfoService.update(user);
        }
//      使用刚注册的账号登录
        if (ObjectUtil.isEmpty(user)) {
            userId = userInfo.getUserId();
            //        运用saToken 加入用户id     设置登录状态
            StpUtil.login(userId);
            //  saToken（存入Account Session中）  在登录时缓存 user 对象
            StpUtil.getSession().set("user" + userId, userInfo);
            //            缓存一些用户的信息  比如是否为  加载token？还是session中
            //        更新用户的上次登录时间
            userInfo.setLastLoginTime(DateUtils.getNowDate());
            userInfoService.update(userInfo);
        }

//        将token信息传递给前端
//        1.获取token信息
        SaTokenInfo tokenInfo = StpUtil.getTokenInfo();

        String token = tokenInfo.getTokenValue();

        UserInfo loginuserInfo = userInfoService.selectById(userId);

        SessionWebDto sessionWebDto = SessionWebDto.builder()
                .nickName(loginuserInfo.getNickName())
                .userId(loginuserInfo.getUserId())
                .isAdmin(ArrayUtil.contains(appConfig.getAdminEmails().split(","), loginuserInfo.getEmail() == null ? "" : loginuserInfo.getEmail()))
                .avatar(loginuserInfo.getAvatar())
                .tokenInfo(token)
                .build();

        StpUtil.getSession().set("WebSession" + userId, sessionWebDto);

        return AjaxResult.success(sessionWebDto);
    }

    /**
     * 重置密码
     *
     * @param resetPasswordDto 电子邮件
     * @return {@link AjaxResult }
     * @author ling
     * @date 2024/11/29
     */
    @PostMapping("resetPassword")
    public AjaxResult resetPwd(@Valid @RequestBody ResetPasswordDto resetPasswordDto) {
        if (ObjectUtil.hasEmpty(resetPasswordDto)) {
            return AjaxResult.error("邮箱数据为空");
        }
        logger.info("重置密码：" + resetPasswordDto);
        //        从数据库中查询 email 是否已经注册过
        UserInfo user = userInfoService.selectByEmail(resetPasswordDto.getEmail());
        logger.info("用户：" + user);
        if (ObjectUtil.isEmpty(user)) {
            return AjaxResult.error("没有邮箱资料");
        }
        if (!resetPasswordDto.getPassword().equals(user.getPassword())) {
            return AjaxResult.error("旧密码错误");
        }
        //        登录  判断eamil 验证码是否正确
        String emailCode = stringRedisTemplate.opsForValue().get(EMAIL_CODE + resetPasswordDto.getEmail());
        if (!resetPasswordDto.getEcode().equals(emailCode)) {
            return AjaxResult.error("验证码错误");
        }

        user.setPassword(resetPasswordDto.getNewpassword());
        userInfoService.update(user);
        return AjaxResult.success("重置成功");
    }

//    登出的功能  注销用户

}

